#include <Log.h>
#include <Hwi.h>
#include <Timer.h>
#include <System.h>
#include <Process.h>

#include <Sos.h>
#include "process.h"

#include "system.h"


//Process_Handler Process_DelayQueue = NULL;
//Process_Handler Process_Sleeping = NULL;
//Process_Handler Process_Current = NULL;


//static inline void Process_statusMark(Process_Status status){
//    SOS.process.status |= (1 << status);
//}
//
//static inline bool Process_statusMarked(Process_Status status){
//    return (SOS.process.status  && (1 << status)) ? true :  false;
//}
//
//static inline Process Process_getEntry(PcbHdl pcb) {
//    return (Process) (pcb->prog & Process_ENTRY_MASK);
//}


//static inline void
//Process_setStatus(
//    PcbHdl          pcb,
//    Process_Status status
//){
//    pcb->status &= ~(Process_STATUS_MASK ^ status);
//}

//static inline
//Process_Status
//Process_getStatus(
//    Process_Handler    pcb
//){
//    return (Process_Status) pcb->sts.val;
//}


//static inline
//Process_Handler
//Process_getNextN(
//    Process_Handler    pcb,
//    Process_Id next
//){
//    while (next) {//assume valid next count & pcb
//        pcb = Process_next(pcb);
//        next--;
//    }
//    return pcb;
//}



Error_Number*
Process_getError(
    Process_Id prog
){
    //return &Process_Pool[prog].error;
    TODO("");//TODO Process_getError

    return NULL;
}

Error_Number
Process_getErrorNumber(
    Process_Id prog
){
    if (Process_SELF == prog)
        prog = Sos.process.current;
    //return Process_Pool[prog].error;
    TODO(""); //TODO Process_getErrorNumber

    return SOK;
}

static inline
void
Process_cutBefore(
    Process_Handler qJumper,
    Process_Handler cut/*ed*/
){
    Process_Handler headx = cut->prev;

    qJumper->prev = headx;
    headx->next = cut->prev = qJumper;
    qJumper->next = cut;
}

Process_Status
Process_cut(
    Process_Id     prog,
    Process_Status action,
    Process_Id     parameter
){
    assert(   (action == Process_CUT_NEXT_N)
           || (action == Process_CUT_BEFORE)
           || (action == Process_CUT_AFTER) );


    Hwi_Key key = Hwi_disable();

    /*ProcessStatus status;
    status.val = ((Process_Handler) prog)->sts.val;*/

    if (Process_haveMark(prog, Process_READY))
        return Process_SOK;

#if 0
    PcbHdl cut = NULL;
    switch (action) {
    case Process_CUT_NEXT_N:
        if (parameter >= sysInfo.process.inscheduler)
            break;//overflowed, cut is unnecessary, keep it auto scheduled.
        cut = Process_getNextN(aim, parameter);
        break;
    case Process_CUT_BEFORE:
        cut = &Process_Pool[Process_Pool[parameter].prev];
        break;
    case Process_CUT_AFTER:
    default:
        cut = &Process_Pool[Process_Pool[parameter].next];
    }
    //priority based cut arbitration.
    while ((cut->attribute & Process_CUT) == Process_CUT) {//TODO FIXME use Process_has(prog, attr)
        if (aim->priority > cut->priority) break;   //a higher priority process can cut a lower one.
        else cut = Process_next(cut);              //try next.
        if ((uint32_t) cut == (uint32_t) aim) {     //we looped back.
            cut = NULL;//cut is unnecessary, keep it auto scheduled.
            break;
    }   }
    if (NULL == cut) {

    }
    //finally, we got one place, remove aim out & cut before.
    Process_remove(aim);
    Process_insert(aim, cut);

    if ((action = Process_getStatus(aim)) != Process_WAIT) {
        switch (action) {
        //TODO
        default:
            action = action;
        }
#endif

    TODO("");

    Hwi_restore(key);
    return Process_SOK;
}


//static
//Uint32 __init
//defaultName(void) {
//    static Process_Id idx = 0;
//    TODO("name from 0-Z");
//    return (Uint32) idx;
//}

//static
//Uint32 __init
//getName(void* arg0) {
//    TODO("name in arg0");
//    return defaultName();
//}

Process_Id
Process_getSelfId(void){
    return Sos.process.current;
}

Process_Id __init
Process_create(
    Process        prog,
    Priority        priority,
    int             argc,
    void*           argv[],
    Process_Status nextStatus  //Process_RUNNING to start immediately, others
){
    Sid idx = 1;
    Process_Handler hp = &Sos.process.pcb[1];
    Process_Handler hm = &Sos.process.pcb[0];

    if (NULL == Sos.process.next) {
        Sos.process.next = hp = hm->next = hm->prev = hm;
        goto Process_addPcb;
    }

    for (/*idx*/; idx < Process_SupportCount; hp++){
        if (NULL == hp->entry) {

            Process_addPcb:
            //hp->name.val = getName(argv[0]);
            hp->pri = priority;
            hp->entry = prog;
            hp->argc = argc;
            hp->argv = argv;

            TODO("more detail add");
            Process_cutBefore(hp, hm);

            return hp;
        }
    }

    return Process_INVALID;
}

Process_Status
Process_suspend(
    Process_Id     pid
){
    Hwi_Key key = Hwi_disable();

    //remove process from ?ready queue
    Process_remove(pid);

    //skip to next if process is next
    if (Sos.process.next == pid)
        Sos.process.next = ((Process_Handler) pid)->next;

    Hwi_restore(key);
    return Process_SOK;
}


Process_Status
Process_resume(        //Resume pid associated process from (mainly in) suspend to ready
    Process_Id     pid
){
    return Process_cut(pid, Process_CUT_BEFORE, Process_MERGE);
}


void
Process_redirect(
    Process_Id pid,
    Process    prog,
    int         argc,
    void*       argv
){
    ((Process_Handler) pid)->entry = prog;
    ((Process_Handler) pid)->argc = argc;
    ((Process_Handler) pid)->argv = argv;
}
